/* sdcard_spi_gpio.c */

#include "sdcard_spi.h"

#include "hal_gpio.h"
#include "hal_lpspi.h"

#include "bsp_config.h"



/* LPSPI传输配置命令模板 */
#define DRV_LPSPI_XFER_COMMAND_DEFAULT_STRUCT {    \
    .PolPhaMode     = eLPSPI_PolPhaMode0,          \
    .ClkDiv         = eLPSPI_ClkDiv_128,            \
    .WhichCS        = 0U,                          \
    .enLSB          = false,                       \
    .enByteSwap     = false,                       \
    .enKeepCS       = false,                       \
    .DataBitsPerCmd = 8U                           \
}

static void    HW_SPI_InitHw(void);
static uint8_t HW_SPI_SwapByte(uint8_t txDat);
static void    HW_SPI_AssertCS(bool enLow);

/* 注册结构体 */
const SDC_SPIHwDrv_T gBspSdcSpiHwDrvStruct =
{
    .SPI_InitHwFunc   = HW_SPI_InitHw,
    .SPI_SwapByteFunc = HW_SPI_SwapByte,
    .SPI_AssertCsFunc = HW_SPI_AssertCS
};

static void HW_SPI_InitHw(void)
{
    LPSPI_MasterConfig_T LpspiMasterConfigStruct =
    {
        .enCSHigh = false,
        .TxFIFOWatermark = 1U,
        .RxFIFOWatermark = 0U
    };
    LPSPI_XferCommand_T LpspiXferCommandStruct = DRV_LPSPI_XFER_COMMAND_DEFAULT_STRUCT;

    /* SPI_CS. */
    GPIO_SetPinLogic(BSP_GPIO_SDCARD_SPI_CS_PORT,   BSP_GPIO_SDCARD_SPI_CS_PIN,   eGPIO_LogicLevel_High);
    GPIO_SetPinDir(BSP_GPIO_SDCARD_SPI_CS_PORT,   BSP_GPIO_SDCARD_SPI_CS_PIN,   eGPIO_Direction_Output);

    /* SPI. */
    LPSPI_HAL_Reset(BSP_SDCARD_LPSPIx);
    LPSPI_HAL_Enable(BSP_SDCARD_LPSPIx, true);
    LPSPI_HAL_ConfigMaster(BSP_SDCARD_LPSPIx, &LpspiMasterConfigStruct);
    LPSPI_HAL_SetXferCommand(BSP_SDCARD_LPSPIx, &LpspiXferCommandStruct); /* Setup the xfer command and never change it later. */
}

static void HW_SPI_Delay(uint32_t timeout)
{
    while (timeout)
    {
        __ASM("NOP");
        timeout--;
    }
}

#define HW_SPI_DELAY_TIMEOUT   1000u

/* MSB, 8bit, SOUT idle low, . */
static uint8_t HW_SPI_SwapByte(uint8_t txDat)
{
    uint8_t rxDat = 0u;
    //uint8_t i;

    HW_SPI_Delay(HW_SPI_DELAY_TIMEOUT);

    LPSPI_HAL_SetTxData(BSP_SDCARD_LPSPIx, txDat);
    while (LPSPI_FLAG_TX_DONE_MASK != LPSPI_HAL_GetStatus(BSP_SDCARD_LPSPIx, LPSPI_FLAG_TX_DONE_MASK))
    {}
    while (LPSPI_FLAG_RX_DONE_MASK != LPSPI_HAL_GetStatus(BSP_SDCARD_LPSPIx, LPSPI_FLAG_RX_DONE_MASK))
    {}
    rxDat = LPSPI_HAL_GetRxData(BSP_SDCARD_LPSPIx);

    HW_SPI_Delay(HW_SPI_DELAY_TIMEOUT);

#if 0
    /* IDLE. */
    //GPIO_SetPinLogic(BSP_GPIO_SDCARD_SPI_SOUT_PORT, BSP_GPIO_SDCARD_SPI_SOUT_PIN, eGPIO_LogicLevel_Low);
    GPIO_SetPinLogic(BSP_GPIO_SDCARD_SPI_CLK_PORT, BSP_GPIO_SDCARD_SPI_CLK_PIN, eGPIO_LogicLevel_Low);
    HW_SPI_Delay(HW_SPI_DELAY_TIMEOUT);

    for (i = 0u; i < 8u; i++)
    {
        /* SOUT 准备数据. */
        if (0u == (txDat & 0x80))
        {
            GPIO_SetPinLogic(BSP_GPIO_SDCARD_SPI_SOUT_PORT, BSP_GPIO_SDCARD_SPI_SOUT_PIN, eGPIO_LogicLevel_Low);
        }
        else
        {
            GPIO_SetPinLogic(BSP_GPIO_SDCARD_SPI_SOUT_PORT, BSP_GPIO_SDCARD_SPI_SOUT_PIN, eGPIO_LogicLevel_High);
        }
        txDat <<= 1u;

        HW_SPI_Delay(HW_SPI_DELAY_TIMEOUT);

        /* CLK 驱动主机数据上线. */
        GPIO_SetPinLogic(BSP_GPIO_SDCARD_SPI_CLK_PORT,  BSP_GPIO_SDCARD_SPI_CLK_PIN,  eGPIO_LogicLevel_High);
        HW_SPI_Delay(HW_SPI_DELAY_TIMEOUT);

        /* CLK 驱动从机数据下线 */
        GPIO_SetPinLogic(BSP_GPIO_SDCARD_SPI_CLK_PORT,  BSP_GPIO_SDCARD_SPI_CLK_PIN,  eGPIO_LogicLevel_Low);
        HW_SPI_Delay(HW_SPI_DELAY_TIMEOUT);

        /* SIN. 捕获数据 */
        if ( eGPIO_LogicLevel_High == GPIO_GetPinLogic(BSP_GPIO_SDCARD_SPI_SIN_PORT,  BSP_GPIO_SDCARD_SPI_SIN_PIN) )
        {
            rxDat |= 1u;
        }
        rxDat <<= 1u;

        /* IDLE. */
        //GPIO_SetPinLogic(BSP_GPIO_SDCARD_SPI_SOUT_PORT, BSP_GPIO_SDCARD_SPI_SOUT_PIN, eGPIO_LogicLevel_Low);
        GPIO_SetPinLogic(BSP_GPIO_SDCARD_SPI_CLK_PORT, BSP_GPIO_SDCARD_SPI_CLK_PIN, eGPIO_LogicLevel_Low);
        HW_SPI_Delay(HW_SPI_DELAY_TIMEOUT);
    }
#endif

    return rxDat;
}

static void HW_SPI_AssertCS(bool enLow)
{
    if (enLow)
    {
        GPIO_SetPinLogic(BSP_GPIO_SDCARD_SPI_CS_PORT,   BSP_GPIO_SDCARD_SPI_CS_PIN,   eGPIO_LogicLevel_Low);
    }
    else
    {
        GPIO_SetPinLogic(BSP_GPIO_SDCARD_SPI_CS_PORT,   BSP_GPIO_SDCARD_SPI_CS_PIN,   eGPIO_LogicLevel_High);
    }
}

/* EOF. */

